﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Windows.Forms;
using System.ComponentModel;
using System.Xml;

namespace GPCodeConjurer
{
	public abstract class Node : INotifyPropertyChanged, ICloneable
	{
		public Node()
		{
			this.GrabHandles = new GrabHandlesCollection();
			this.StartFigure = false;
			this.CloseFigure = false;
		}

		public Node(XmlElement seralizedNode)
			: this()
		{
		}


		public GraphicsPathEditor Editor { get; internal set; }

		private bool startFigure = false;
		public virtual bool StartFigure
		{
			get
			{
				return this.startFigure;
			}
			set
			{
				if (this.startFigure != value)
				{
					this.startFigure = value;
					if (this.Editor != null)
						this.Editor.Invalidate();
				}
			}
		}

		private bool closeFigure = false;
		public virtual bool CloseFigure
		{
			get
			{
				return this.closeFigure;
			}
			set
			{
				if (this.closeFigure != value)
				{
					this.closeFigure = value;
					if (this.Editor != null)
						this.Editor.Invalidate();
				}
			}
		}

		internal bool selected = false;
		public virtual bool Selected
		{
			get
			{
				return selected;
			}
			set
			{
				this.selected = value;
				this.Editor.SelectedNode = this;
			}
		}


		internal abstract Rectangle Rect { get; }

		internal GrabHandlesCollection GrabHandles { get; set; }

		internal abstract void DrawPath(GraphicsPath gp);

		internal abstract void OnGrabHandleMove(HandleMovedEventArgs grabHandle);

		internal abstract void OnMoved(NodeMovedEventArgs e);

		public abstract string CreateCode();

		public abstract XmlElement Serialize(XmlDocument xmlDoc);

		public abstract void Deserialize(XmlElement seralizedElement);

		public void ScrollIntoPosition()
		{
			// Add logic.
		}


		/// <summary>
		/// Remove the node from the canvas.
		/// </summary>
		public virtual void Remove()
		{
			if (this.Editor != null)
			{
				this.Editor.RemoveNode(this);
			}
		}


		internal virtual void DrawGrabHandles(Graphics g)
		{
			if (this.selected)
			{
				foreach (var kvp in this.GrabHandles)
				{
					kvp.Value.PaintGrabHandle(g);
				}
			}
		}


		internal virtual GrabHandle GetHandleAtPoint(Point pt)
		{
			if (!this.selected)
				return null;
			foreach (var kvp in this.GrabHandles)
			{
				if (kvp.Value.Rect.Contains(pt))
				{
					return kvp.Value;
				}
			}
			return null;
		}


		internal virtual bool PointIsOnSelectionFrame(Point pt)
		{
			var rect = this.Rect.Absolute();
			return (Rectangle.Inflate(rect, GrabHandle.GrabHandleSize, GrabHandle.GrabHandleSize).Contains(pt) && !Rectangle.Inflate(rect, 0, 0).Contains(pt));
		}



		/// <summary>
		/// Code to determine whether a point is on the nodes line and if it should be selected on that point.
		/// </summary>
		/// <param name="pt"></param>
		/// <returns></returns>
		internal abstract bool PointIsOnNode(Point pt);


		internal virtual void RelocateGrabHandles()
		{
		}


		protected virtual void NotifyPropertyChanged(string name)
		{
			if (this.PropertyChanged != null)
			{
				this.PropertyChanged(this, new PropertyChangedEventArgs(name));
			}
		}


		public virtual void Invalidate()
		{
			if (this.Editor != null)
				this.Editor.Invalidate();
		}



		#region INotifyPropertyChanged Members

		public event PropertyChangedEventHandler PropertyChanged;

		#endregion

		#region ICloneable Members

		public abstract object Clone();

		#endregion
	}



}
